﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows.Data;
using SharedCode;
using AdminModule.IndexMarkServiceReference;
using InpValidator;
using AdminModule.ViewModels;
using AdminModule.CommonClasses;

namespace AdminModule.Views
{
    public enum EditMode { Add, Edit, Delete };

    public partial class EditWindow : ChildWindow
    {
        private ViewName viewName;
        private EditWindowVM viewModel;
        private EditMode editMode;

        public delegate void SaveCompleted(ViewName viewName);
        public event SaveCompleted SaveCompletedEvent;

        public delegate void SaveMethodDelegate();
        private SaveMethodDelegate SaveMethod;

        // Коллекция элементов ComboBox, инициализацию которых необходимо вызвать после загрузки списка из базы
        // В эту коллекцию будут помещаться ссылка на ComboBox и метод, который необходимо вызвать для его инициализации
        private Dictionary<ComboBox, ComboBoxInitParams> comboBoxList = new Dictionary<ComboBox, ComboBoxInitParams>();

        // Переданные объекты для удаления
        private System.Collections.IEnumerable deletedObjects;

        public EditWindow(ViewName viewName, EditMode editMode, ViewModelBase foreignViewModel = null)
        {
            InitializeComponent();

            this.viewName = viewName;
            this.editMode = editMode;
            viewModel = this.Resources["viewModel"] as EditWindowVM;
            viewModel.foreignViewModel = foreignViewModel;

            Init(viewName);

            // Если передана модель представления для загрузки данных, значит, необходимо выполнить ее инициализацию
            if (foreignViewModel != null)
            {
                foreignViewModel.InitStarted += () =>
                    {
                        progressBar.SetDefaultText();
                        progressBar.IsVisibility = Visibility.Visible;
                    };
                foreignViewModel.InitCompleted += () =>
                    {
                        ComboBoxLazyInitStart();
                        progressBar.IsVisibility = Visibility.Collapsed;
                    };
                foreignViewModel.Init();
            }

            // Устанавливаем заголовок
            switch (editMode)
            {
                case EditMode.Add:
                    this.Title = "Добавление записи";
                    break;
                case EditMode.Edit:
                    this.Title = "Редактирование записи";
                    break;
            }
        }

        private void ComboBoxLazyInitPrepare(object sender, ComboBoxInitParams p)
        {
            if (!comboBoxList.Keys.Contains(sender as ComboBox))
            {
                comboBoxList.Add(sender as ComboBox, p);
            }
        }

        private void ComboBoxLazyInitStart()
        {
            foreach (var i in comboBoxList)
            {
                i.Value.LoadedMethod(i.Key, i.Value.e);
            }
        }

        private void Init(ViewName viewName)
        {
            switch (viewName)
            {
                case ViewName.AdmUnit:
                    SetTemplate("AdmUnit");
                    SaveMethod = () => 
                    {
                        viewModel.client.SaveAdmUnitAsync(this.GenerateCollection<AdmUnit>());
                    };
                    viewModel.client.SaveAdmUnitCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmTerm:
                    SetTemplate("AdmTerm");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmTermAsync(this.GenerateCollection<AdmTerm>());
                    };
                    viewModel.client.SaveAdmTermCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmDegree:
                    SetTemplate("AdmDegree");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmDegreeAsync(this.GenerateCollection<AdmDegree>());
                    };
                    viewModel.client.SaveAdmDegreeCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmDepartmentType:
                    SetTemplate("AdmDepartmentType");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmDepartmentTypesAsync(this.GenerateCollection<AdmDepartmentType>());
                    };
                    viewModel.client.SaveAdmDepartmentTypesCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmPerson:
                    SetTemplate("AdmPerson");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmPersonAsync(this.GenerateCollection<AdmPerson>());
                    };
                    viewModel.client.SaveAdmPersonCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmJob:
                    SetTemplate("AdmJob");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmJobAsync(this.GenerateCollection<AdmJob>());
                    };
                    viewModel.client.SaveAdmJobCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmStatus:
                    SetTemplate("AdmStatus");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmStatusAsync(this.GenerateCollection<AdmStatus>());
                    };
                    viewModel.client.SaveAdmStatusCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmPosition:
                    SetTemplate("AdmPosition");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmPositionAsync(this.GenerateCollection<AdmPosition>());
                    };
                    viewModel.client.SaveAdmPositionCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmCategoriesByTerm:
                    SetTemplate("AdmCategoriesByTerm");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmCategoriesByTermAsync(this.GenerateCollection<AdmCategory>());
                    };
                    viewModel.client.SaveAdmCategoriesByTermCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmResponsible:
                    SetTemplate("AdmResponsible");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmResponsibleAsync(this.GenerateCollection<AdmResponsible>());
                    };
                    viewModel.client.SaveAdmResponsibleCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmCharacteristic:
                    SetTemplate("AdmCharacteristic");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmCharacteristicAsync(this.GenerateCollection<AdmCharacteristic>());
                    };
                    viewModel.client.SaveAdmCharacteristicCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmDepartment:
                    SetTemplate("AdmDepartment");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmDepartmentAsync(this.GenerateCollection<AdmDepartment>());
                    };
                    viewModel.client.SaveAdmDepartmentCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmSection:
                    SetTemplate("AdmSection");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmSectionAsync(this.GenerateCollection<AdmSection>());
                    };
                    viewModel.client.SaveAdmSectionCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmCategory:
                    SetTemplate("AdmCategory");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmCategoryAsync(this.GenerateCollection<AdmCategory>());
                    };
                    viewModel.client.SaveAdmCategoryCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;

                case ViewName.AdmGradation:
                    SetTemplate("AdmGradation");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmGradationAsync(this.GenerateCollection<AdmGradation>());
                    };
                    viewModel.client.SaveAdmGradationCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;
                case ViewName.AdmPersonDegree:
                    SetTemplate("AdmPersonDegree");
                    SaveMethod = () =>
                    {
                        viewModel.client.SaveAdmPersonDegreesAsync(this.GenerateCollection<AdmPersonDegree>());
                    };
                    viewModel.client.SaveAdmPersonDegreesCompleted += (s, ev) => { client_SaveCompleted(s, ev); };
                    break;
                default:
                    throw new Exception("Такой шаблон не реализован");
            }
        }

        private void SetTemplate(string templateName)
        {
            editDataForm.EditTemplate = this.Resources[templateName] as DataTemplate;
        }

        private void client_SaveCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            progressBar.IsVisibility = Visibility.Collapsed;

            if (e.Error != null)
            {
                ErrorWindow.Show(e.Error);
            }
            else
            {
                if (SaveCompletedEvent != null)
                {
                    SaveCompletedEvent(this.viewName);
                }
                this.DialogResult = true;
            }
        }

        private void editDataForm_EditEnded(object sender, DataFormEditEndedEventArgs e)
        {
            switch (editMode)
            {
                case EditMode.Delete:
                    progressBar.Text = "Удаление записей...";
                    break;
                default:
                    progressBar.Text = "Сохранение данных...";
                    break;
            }
            
            progressBar.IsVisibility = Visibility.Visible;
            SaveMethod();
        }

        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
        }

        private void SetCurrentObject(object currentObject)
        {
            this.viewModel.objectForEdit = ObjectClone.Clone<object>(currentObject);
        }

        private void SetCurrentObject(System.Collections.IEnumerable collection)
        {
        }

        public void Show(object currentObject) 
        {
            this.SetCurrentObject(currentObject);
            base.Show();
        }

        public void Show(System.Collections.IEnumerable deletedObjects)
        {
            this.deletedObjects = deletedObjects;
            MessageBoxResult f = MessageBox.Show("Удалить?", MyAssemblyInfo.Title, MessageBoxButton.OKCancel);
            if (f == MessageBoxResult.OK)
            {
                this.editDataForm_EditEnded(null, null);
            }
        }

        /// <summary>
        /// Создает коллекцию объектов, которые необходимо отправить web-сервису
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        private ObservableCollection<T> GenerateCollection<T>()
        {
            ObservableCollection<T> coll = new ObservableCollection<T>();

            if (this.deletedObjects == null)
            {
                coll.Add((T)this.viewModel.objectForEdit);
            }
            else
            {
                foreach (var el in this.deletedObjects)
                {
                    coll.Add((T)el);
                }
            }

            return coll;
        }

        private void positionComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = positionComboBox_Loaded, e = e });

            int IDPosition = 0;

            if (b.Tag == null) return;

            if (b.Tag is AdmJob)
            {
                AdmJob job = b.Tag as AdmJob;
                if (job.Position == null) return;
                IDPosition = job.Position.IDPosition;
            }
            if (b.Tag is AdmResponsible)
            {
                AdmResponsible responsible = b.Tag as AdmResponsible;
                if (responsible.Position == null) return;
                IDPosition = responsible.Position.IDPosition;
            }
            
            IEnumerable<AdmPosition> list = b.ItemsSource.Cast<AdmPosition>();
            b.SelectedItem = list.FirstOrDefault(f => f.IDPosition == IDPosition);
        }

        private void statusComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = statusComboBox_Loaded, e = e });

            AdmJob job = b.Tag as AdmJob;
            IEnumerable<AdmStatus> list = b.ItemsSource.Cast<AdmStatus>();
            if (job == null || job.Status == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.IDStatus == job.Status.IDStatus);
        }

        private void positionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            if (b.Tag is AdmJob)
            {
                AdmJob job = b.Tag as AdmJob;
                job.Position = b.SelectedItem as AdmPosition;
            }
            if (b.Tag is AdmResponsible)
            {
                AdmResponsible responsible = b.Tag as AdmResponsible;
                responsible.Position = b.SelectedItem as AdmPosition;
            }
        }

        private void statusComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmJob job = b.Tag as AdmJob;
            job.Status = b.SelectedItem as AdmStatus;
        }

        private void departmentComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = departmentComboBox_Loaded, e = e });

            AdmResponsible resp = b.Tag as AdmResponsible;
            IEnumerable<AdmDepartment> list = b.ItemsSource.Cast<AdmDepartment>();
            if (resp.Department == null) return;
            // Отдел может быть = null
            IEnumerable<AdmDepartment> tmplist = b.ItemsSource.Cast<AdmDepartment>();
            tmplist = list.Where(w => w != null);
            b.SelectedItem = tmplist.FirstOrDefault(f => f.IDDepartment == resp.Department.IDDepartment);
        }

        private void departmentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmResponsible resp = b.Tag as AdmResponsible;
            resp.Department = b.SelectedItem as AdmDepartment;
        }

        private void gradationComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = gradationComboBox_Loaded, e = e });

            AdmGradation gradation = b.Tag as AdmGradation;
            IEnumerable<AdmGradation> list = b.ItemsSource.Cast<AdmGradation>();
            if (gradation == null || list == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.ID == gradation.ID);
        }

        private void gradationComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmGradation gradation = b.Tag as AdmGradation;
            if (b.SelectedItem == null) return;
            gradation.ID = (b.SelectedItem as AdmGradation).ID;
        }

        private void categoryComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = categoryComboBox_Loaded, e = e });

            AdmCategory category = b.Tag as AdmCategory;
            IEnumerable<AdmCategory> list = b.ItemsSource.Cast<AdmCategory>();
            if(category == null || list == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.IDCategory == category.IDCategory);
        }

        private void categoryComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmCategory category = b.Tag as AdmCategory;
            if (b.SelectedItem == null) return;
            category.IDCategory = (b.SelectedItem as AdmCategory).IDCategory;
        }

        public void InitValidator(object sender, RoutedEventArgs e)
        {
            ValidatorBase v = sender as ValidatorBase;
            v.SetEnvironment(LayoutRoot, editDataForm, MainManager);
        }

        private void editDataForm_EditEnding(object sender, DataFormEditEndingEventArgs e)
        {
            if (this.MainManager.ValidateAll().Count > 0)
            {
                e.Cancel = true;
                MessageBox.Show("Некоторые поля заполнены некорректно", MyAssemblyInfo.Title, MessageBoxButton.OK);
            }
        }

        private void typeDepartmentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox cb = sender as ComboBox;
            if (cb.SelectedItem == null) return;

            (cb.Tag as AdmDepartment).DepartmentType = cb.SelectedItem as AdmDepartmentType;
        }

        private void typeDepartmentComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = typeDepartmentComboBox_Loaded, e = e });

            AdmDepartmentType depType = (b.Tag as AdmDepartment).DepartmentType;
            IEnumerable<AdmDepartmentType> list = b.ItemsSource.Cast<AdmDepartmentType>();
            if (depType == null || list == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.ID == depType.ID);
        }

        private void degreeComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = degreeComboBox_Loaded, e = e });

            AdmPersonDegree personDegree = b.Tag as AdmPersonDegree;
            IEnumerable<AdmDegree> list = b.ItemsSource.Cast<AdmDegree>();
            if (personDegree == null || personDegree.Degree == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.ID == personDegree.Degree.ID);
        }

        private void degreeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmPersonDegree personDegree = b.Tag as AdmPersonDegree;
            if (b.SelectedItem == null) return;
            personDegree.Degree = (b.SelectedItem as AdmDegree);
        }

        private void personForDegreeComboBox_Loaded(object sender, RoutedEventArgs e)
        {
            ComboBox b = sender as ComboBox;
            ComboBoxLazyInitPrepare(sender, new ComboBoxInitParams { LoadedMethod = personForDegreeComboBox_Loaded, e = e });

            AdmPersonDegree personDegree = b.Tag as AdmPersonDegree;
            if (b.ItemsSource == null) return;
            IEnumerable<AdmPerson> list = b.ItemsSource.Cast<AdmPerson>();
            if (personDegree == null || personDegree.Person == null) return;
            b.SelectedItem = list.FirstOrDefault(f => f.IDPerson== personDegree.Person.IDPerson);
        }

        private void personForDegreeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ComboBox b = sender as ComboBox;

            AdmPersonDegree personDegree = b.Tag as AdmPersonDegree;
            if (b.SelectedItem == null) return;
            personDegree.Person = (b.SelectedItem as AdmPerson);
        }
    }

    public class ComboBoxInitParams
    {
        public delegate void LoadedMethodDelegate(object sender, RoutedEventArgs e);
        public LoadedMethodDelegate LoadedMethod { get; set; }
        public RoutedEventArgs e { get; set; }
    }
}

